package com.mkl.ttxt.pd.util;

import com.alibaba.fastjson.JSON;
import com.mkl.ttxt.common.constant.BaseConstant;
import com.mkl.ttxt.common.exception.BusinessException;
import com.mkl.ttxt.pd.bo.*;
import com.mkl.ttxt.pd.dao.IPdDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Component
public class PlanUtil {

    @Autowired
    private static IPdDao iPdDao;

    @Autowired
    private static BaseConstant baseConstant;

    private static List<Target> targetList;

    private static List<LineupCompose> lineupComposeList = new ArrayList<>();

    private static Integer lastMinBlood;

    private static List<Lineup> lineupList;

    private static Long count;

    private static Integer resultCount;

    private static Double minVariance;

    private static boolean excuteFlag = false;

    @Autowired
    public PlanUtil(IPdDao iPdDao, BaseConstant baseConstant) {
        PlanUtil.iPdDao = iPdDao;
        PlanUtil.baseConstant = baseConstant;
    }

    public static void planning(List<Target> targetList, Integer userId) throws Exception {
        if(excuteFlag){
            throw new BusinessException("正在自动排刀，请稍后");
        }
        PlanUtil.lineupList = iPdDao.getAllLineup(userId);
        //设置目标
        for(Target target: targetList){
            if(target.getRemainBlood() == null || target.getRemainBlood() ==0){
                target.setRemainBlood(target.getTotalBlood());
            }
            PlanUtil.lastMinBlood = target.getTotalBlood();
        }
        PlanUtil.targetList = targetList;

        List<MemberOrCard> memberList = iPdDao.getAllMember(userId);
        //算法剪枝
        cutBranch();
        excuteFlag = true;
        resultCount = 0;
        count = Long.valueOf(0);
        minVariance = null;
        try{
            //初始化参数
            baseConstant.loadBloodParam(userId);
            calMemberI(memberList, 0, userId);
            if(resultCount < 1){
                throw new BusinessException("尝试" + count + "次后无法达成目标");
            }
        }catch (Exception e){
            System.out.println(e.getMessage());
            excuteFlag = false;
            throw e;
        }
        excuteFlag = false;
    }

    private static void cutBranch() {
        try{
            //备份现有出刀组合
//            iPdDao.backupCompose();

        }catch (Exception e){
            throw new BusinessException("成员出刀备份表仍有数据");
        }

    }

    private static void calMemberI(List<MemberOrCard> memberList, int i, Integer userId) throws IOException {
        //如果30人出完，判断阵容效果，若比之前优秀，记录
        if(i >= 30){
            //理想情况，全排好
            //检查除最后一个外打完没
            if(checkTarget()){
                //最后一个打了多少
                Target lastTarget = PlanUtil.targetList.get(PlanUtil.targetList.size()-1);
                //如果比之前好，入库，更新最佳记录
                if(lastTarget.getRemainBlood() < PlanUtil.lastMinBlood){
//                    iPdDao.cleanResult();
                    resultCount++;
                    System.out.println("已生成第" + resultCount + "次结果");
                    PlanUtil.lastMinBlood = lastTarget.getRemainBlood();
//                    iPdDao.recordResult(PlanUtil.lineupComposeList);
                    //写文件
                    recordResult("Final", userId);
                }
            }
            return;
        }
        if(i >= BaseConstant.TEMPFILE_MEMBER_NUM){
            //现实情况，最后留几个人灵活调配
            //除最后一个BOSS外，剩余血量方差越小越好
            List<Integer> remainBloodList = new ArrayList<>();
            for(int j=0;j<PlanUtil.targetList.size()-1;j++){
                Target target = PlanUtil.targetList.get(j);
                remainBloodList.add(target.getRemainBlood());
            }
            //计算方差
            Double variance = calVariance(remainBloodList);
            if(minVariance == null || variance < minVariance){
                minVariance = variance;
                recordResult("Temp" + i, userId);
            }
        }
        MemberOrCard member = memberList.get(i);
        List<LineupCompose> lineupComposeList = iPdDao.getUserSetMeal(member.getId(), userId);
        for(LineupCompose lineupCompose: lineupComposeList){
            lineupCompose.setMemberId(member.getId());
            lineupCompose.setMemberIds(null);
            lineupCompose.setLineup1Detail(getLineup(lineupCompose.getLineup1()));
            lineupCompose.setLineup2Detail(getLineup(lineupCompose.getLineup2()));
            lineupCompose.setLineup3Detail(getLineup(lineupCompose.getLineup3()));
//            lineupCompose.setLineup1Detail(iPdDao.getLineupById(lineupCompose.getLineup1()));
//            lineupCompose.setLineup2Detail(iPdDao.getLineupById(lineupCompose.getLineup2()));
//            lineupCompose.setLineup3Detail(iPdDao.getLineupById(lineupCompose.getLineup3()));
            if(checkLineupCompose(lineupCompose)){
                excuteLinueupCompose(lineupCompose, i);
                calMemberI(memberList, i + 1, userId);
                callbackLinueupCompose(lineupCompose);
            }
        }
    }

    private static Double calVariance(List<Integer> remainBloodList) {
        double avr = 0;
        double sum1 = 0;
        double sum2 = 0;
        double sum3 = 0;
        for(Integer remainBlood: remainBloodList){
            sum1 = remainBlood;
            sum2 = sum1 + sum2;
        }
        avr = sum2/(remainBloodList.size() - 1);
        sum1 = 0;
        sum2 = 0;
        for(Integer remainBlood: remainBloodList){
            sum1 = avr - remainBlood;
            sum2 = Math.pow(sum1, 2);
            sum3 = sum2 + sum3;
        }
        avr =sum3/(remainBloodList.size() - 1);
        return avr;
    }

    private static void recordResult(String state, Integer userId) throws IOException {
        String content = getResultContent();
        File file = new File(userId + "result" + state + ".csv");
        if(!file.exists()){
            file.createNewFile();
        }
        FileWriter fileWritter = new FileWriter(file.getName(),true);
        fileWritter.write(content);
        fileWritter.close();
    }

    private static String getResultContent() {
        String result = "BOSS状态：\r\n";
        for(Target target: PlanUtil.targetList){
            result += target.getBossNo() + "王目标：" + target.getTotalBlood() + "万，剩余:" + target.getRemainBlood() + "万\r\n";
        }
        result += "排刀结果:\r\n";
        Integer totalScore = 0;
        for(LineupCompose lineupCompose: PlanUtil.lineupComposeList){
            lineupCompose.setLineup1Detail(getLineupDetail(lineupCompose.getLineup1Detail()));
            lineupCompose.setLineup2Detail(getLineupDetail(lineupCompose.getLineup2Detail()));
            lineupCompose.setLineup3Detail(getLineupDetail(lineupCompose.getLineup3Detail()));
            lineupCompose.setMemberNames(iPdDao.getMembersByIds(new ArrayList<String>(Arrays.asList(String.valueOf(lineupCompose.getMemberId())))));

            result += lineupCompose.getMemberNames() + "|";
            result += lineupCompose.getLineup1Detail().getBossNo() + "王|" +
                    lineupCompose.getLineup1Detail().getDamage() + "|";
            for(LineupCard lineupCard: lineupCompose.getLineup1Detail().getLineupCardList()){
                result += lineupCard.getStar() + "星" + lineupCard.getCardName() + "/" ;
            }
            result += "|";
            result += lineupCompose.getLineup2Detail().getBossNo() + "王|" +
                    lineupCompose.getLineup2Detail().getDamage() + "|";
            for(LineupCard lineupCard: lineupCompose.getLineup2Detail().getLineupCardList()){
                result += lineupCard.getStar() + "星" + lineupCard.getCardName() + "/";
            }
            result += "|";
            result += lineupCompose.getLineup3Detail().getBossNo() + "王|" +
                    lineupCompose.getLineup3Detail().getDamage() + "|";
            for(LineupCard lineupCard: lineupCompose.getLineup3Detail().getLineupCardList()){
                result += lineupCard.getStar() + "星" + lineupCard.getCardName() + "/";
            }
            result += "\r\n";
            totalScore += lineupCompose.getScore();
        }
        result += "总分：" + totalScore + "\r\n";
        result += "----------------------------------------------------------------------------------------\r\n";
        return result;
    }

    private static Lineup getLineupDetail(Lineup lineup) {
        List<LineupCard> cardList = JSON.parseArray(lineup.getLineup(), LineupCard.class);
        if(cardList == null || cardList.size() < 1){
            lineup.setLineup(null);
            return lineup;
        }
        for (LineupCard card : cardList) {
            card.setCardName(iPdDao.getCardName(card.getCardId()));
        }
        lineup.setLineup(null);
        lineup.setLineupCardList(cardList);
        return lineup;
    }

    private static Lineup getLineup(Integer lineup1) {
        for(Lineup lineup :PlanUtil.lineupList){
            if(lineup.getId().equals(lineup1)){
                return lineup;
            }
        }
        return null;
    }

    //判断这刀能不能出
    private static boolean checkLineupCompose(LineupCompose lineupCompose) {
        PlanUtil.count++;
        if(PlanUtil.count % 10000000 == 0){
            System.out.println("次数：" + count + ",时间：" + System.currentTimeMillis());
        }
//        if(PlanUtil.count > 2000000000){
//            throw new BusinessException("尝试次数已超出20亿次，自动停止，可在现有方案中选取");
//        }
        //检查BOSS血够不够
        Lineup lineup1 = lineupCompose.getLineup1Detail();
        boolean lineup1Flag = false;
        Lineup lineup2 = lineupCompose.getLineup2Detail();
        boolean lineup2Flag = false;
        Lineup lineup3 = lineupCompose.getLineup3Detail();
        boolean lineup3Flag = false;
        boolean result = false;
        boolean bossAllDown = true;
        for(Target target: PlanUtil.targetList){
            if(target.getRemainBlood() > baseConstant.BLOOD_LINE){
                bossAllDown = false;
            }
            if(!lineup1Flag && target.getBossNo().equals(lineup1.getBossNo())){
                if(target.getRemainBlood() > baseConstant.BLOOD_LINE){
                    lineup1Flag = true;
                    continue;
                }
            }
            if(!lineup2Flag && target.getBossNo().equals(lineup2.getBossNo())){
                if(target.getRemainBlood() > baseConstant.BLOOD_LINE){
                    lineup2Flag = true;
                    continue;
                }
            }
            if(!lineup3Flag && target.getBossNo().equals(lineup3.getBossNo())){
                if(target.getRemainBlood() > baseConstant.BLOOD_LINE){
                    lineup3Flag = true;
                    continue;
                }
            }
        }
        if(!lineup1Flag && !lineup2Flag && !lineup3Flag){
            result = false;
        }

        if(lineup1Flag && lineup2Flag && lineup3Flag){
            result = true;
        }
        if(bossAllDown){
            throw new BusinessException("BOSS血量不足，请重新设定目标");
        }
        return result;
    }

    //出这刀
    private static void excuteLinueupCompose(LineupCompose lineupCompose, int i){
        //扣BOSS血
        Lineup lineup1 = lineupCompose.getLineup1Detail();
        boolean lineup1Flag = false;
        Lineup lineup2 = lineupCompose.getLineup2Detail();
        boolean lineup2Flag = false;
        Lineup lineup3 = lineupCompose.getLineup3Detail();
        boolean lineup3Flag = false;
        for(Target target: PlanUtil.targetList){
            if(!lineup1Flag && target.getBossNo().equals(lineup1.getBossNo())
                    && (target.getRemainBlood() > baseConstant.BLOOD_LINE)
            ){
                target.setRemainBlood(target.getRemainBlood() - lineup1.getDamage());
                lineup1Flag = true;
                continue;
            }
            if(!lineup2Flag && target.getBossNo().equals(lineup2.getBossNo())
                    && (target.getRemainBlood() > baseConstant.BLOOD_LINE)
            ){
                target.setRemainBlood(target.getRemainBlood() - lineup2.getDamage());
                lineup2Flag = true;
                continue;
            }
            if(!lineup3Flag && target.getBossNo().equals(lineup3.getBossNo())
                    && (target.getRemainBlood() > baseConstant.BLOOD_LINE)
            ){
                target.setRemainBlood(target.getRemainBlood() - lineup3.getDamage());
                lineup3Flag = true;
                continue;
            }
        }
        if(!lineup1Flag || !lineup2Flag || !lineup3Flag){
            throw new BusinessException("出刀失败");
        }
        //记录这一刀
        PlanUtil.lineupComposeList.add(lineupCompose);

    }

    private static boolean checkTarget() {
        boolean result = true;
        for(int i=0;i<PlanUtil.targetList.size()-1;i++){
            Target target = PlanUtil.targetList.get(i);
            if(target.getRemainBlood() > baseConstant.BLOOD_LINE){
                result = false;
            }
        }
        String content = getResultContent();
        return result;
    }

    //撤回这刀
    private static void callbackLinueupCompose(LineupCompose lineupCompose){
        //回BOSS血
        Lineup lineup1 = lineupCompose.getLineup1Detail();
        boolean lineup1Flag = false;
        Lineup lineup2 = lineupCompose.getLineup2Detail();
        boolean lineup2Flag = false;
        Lineup lineup3 = lineupCompose.getLineup3Detail();
        boolean lineup3Flag = false;
        for(int i = PlanUtil.targetList.size() - 1; i >= 0; i--){
            Target target = PlanUtil.targetList.get(i);
            if(!lineup1Flag && target.getBossNo().equals(lineup1.getBossNo())
                    && ((target.getRemainBlood() + lineup1.getDamage()) <= target.getTotalBlood() + BaseConstant.REPLY_OVERFLOW)){
                //回血
                target.setRemainBlood(target.getRemainBlood() + lineup1.getDamage());
                lineup1Flag = true;
            }
            if(!lineup2Flag && target.getBossNo().equals(lineup2.getBossNo())
                    && ((target.getRemainBlood() + lineup2.getDamage()) <= target.getTotalBlood() + BaseConstant.REPLY_OVERFLOW)){
                //回血
                target.setRemainBlood(target.getRemainBlood() + lineup2.getDamage());
                lineup2Flag = true;
            }
            if(!lineup3Flag && target.getBossNo().equals(lineup3.getBossNo())
                    && ((target.getRemainBlood() + lineup3.getDamage()) <= target.getTotalBlood() + BaseConstant.REPLY_OVERFLOW)){
                //回血
                target.setRemainBlood(target.getRemainBlood() + lineup3.getDamage());
                lineup3Flag = true;
            }
        }
        if(!lineup3Flag || !lineup2Flag || !lineup1Flag){
            throw new BusinessException("撤回失败");
        }
        //删除出刀记录(最后一刀)
        PlanUtil.lineupComposeList.remove(PlanUtil.lineupComposeList.get(PlanUtil.lineupComposeList.size()-1));
    }
}
